package seatiger.tomcat.coyote.http11;

import seatiger.tomcat.catalina.Constants;
import seatiger.tomcat.coyote.ActionCode;
import seatiger.tomcat.coyote.OutputBuffer;
import seatiger.tomcat.coyote.Response;
import seatiger.tomcat.util.buf.ByteChunk;

import java.io.IOException;
import java.io.OutputStream;

/**
 * 输出缓冲装置
 */
public class InternalOutputBuffer implements OutputBuffer {

    /**
     * 报文头的输出
     */
    protected byte[] buf;

    /**
     * buf中的位置
     */
    protected int pos;

    /**
     * 底层的输出流
     */
    protected OutputStream outputStream;

    /**
     * 关联的coyote Response
     */
    protected Response response;

    /**
     * 输出过滤器库
     */
    protected OutputFilter[] filterLibrary;

    /**
     * 活动的输出过滤器
     */
    protected OutputFilter[] activeFilters;

    /**
     * 活动的过滤器
     */
    protected int lastActiveFilter = 0;

    /**
     * 底层的输出流buffer
     */
    protected OutputBuffer outputStreamOutputBuffer;

    private boolean finished;

    /**
     * 是否提交过标志
     * 如果 ByteChunk中buf 容量满了之后，就要提交刷出报文体数据，
     * 刷出报文体数据之前，需要把头部信息 先刷出。这个标志控制的是否提交过头部信息
     *
     * 程序结束之后，还需要把报文体的数据刷出，这个时候就不需要刷报文头了
     */
    protected boolean committed;


    public void setOutputStream(OutputStream outputStream) {
        this.outputStream = outputStream;
    }

    public InternalOutputBuffer(Response response, int headerBufferSize) {
        this.response = response;
        buf = new byte[headerBufferSize];
        outputStreamOutputBuffer = new OutputStreamOutputBuffer();
        filterLibrary = new OutputFilter[0];
        activeFilters = new OutputFilter[0];
        lastActiveFilter = -1;
        finished = false;
        committed = false;
    }

    public void addFilter(OutputFilter filter) {
        OutputFilter[] newFilterLibrary = new OutputFilter[filterLibrary.length + 1];
        for (int i = 0; i < filterLibrary.length; i++) {
            newFilterLibrary[i] = filterLibrary[i];
        }
        newFilterLibrary[filterLibrary.length] = filter;
        filterLibrary = newFilterLibrary;
        activeFilters = new OutputFilter[filterLibrary.length];
    }

    /**
     * 添加活动的过滤器
     */
    public void addActiveFilter(OutputFilter filter) {
        if (lastActiveFilter == -1) {
            filter.setBuffer(outputStreamOutputBuffer);
        }else {
            for (int i = 0; i <= lastActiveFilter; i++) {
                if (activeFilters[i] == filter)
                    return;
            }
            filter.setBuffer(activeFilters[lastActiveFilter]);

        }
        activeFilters[++lastActiveFilter] = filter;
        filter.setResponse(response);
    }

    public OutputFilter[] getFilters() {
        return filterLibrary;
    }

    /**
     * 写出相应码
     */
    public void sendStatus() {
        //将协议出去
        write(Constants.HTTP_11_BYTES);
        buf[pos++] = Constants.SP;
        //TODO 获取响应码  先默认200
        int status = response.getStatus();
        switch (status) {
            case 200:
                write(Constants._200_BYTES);
        }
        buf[pos++] = Constants.SP;
        //TODO
        String message = "OK";
        write(message);
        //回车换行
        buf[pos++] = Constants.CR;
        buf[pos++] = Constants.LF;
    }

    public void sendHeader(String name, String value) {
        write(name);
        buf[pos++] = Constants.COLON;
        buf[pos++] = Constants.SP;
        write(value);
        buf[pos++] = Constants.CR;
        buf[pos++] = Constants.LF;
    }

    public void endHeaders() {
        buf[pos++] = Constants.CR;
        buf[pos++] = Constants.LF;
    }

    /**
     * 用于写出报文头的数组，将字节数组写到buf中
     *
     * @param b
     */
    public void write(byte[] b) {
        System.arraycopy(b, 0, buf, pos, b.length);
        pos += b.length;
    }

    /**
     * 写出字符串
     *
     * @param value
     */
    protected void write(String value) {
        if (value == null) {
            return;
        }
        for (int i = 0; i < value.length(); i++) {
            char c = value.charAt(i);
            if ((c <= 31) && (c != 9)) {
                c = ' ';
            } else if (c == 127) {
                c = ' ';
            }
            buf[pos++] = (byte) c;
        }
    }

    //输出报文头
    public void commit() throws IOException {
        committed = true;
        response.setCommited(true);
        if (pos > 0) {
            outputStream.write(buf, 0, pos);
        }
    }

    @Override
    public int doWrite(ByteChunk chunk, Response response) throws IOException {
        //如果没有提交过报文头，需要先提交报文头
        if (!committed) {
            response.action(ActionCode.ACTION_COMMIT);
        }
        if (lastActiveFilter == -1) {
            return outputStreamOutputBuffer.doWrite(chunk,response);
        }else {
            return activeFilters[lastActiveFilter].doWrite(chunk,response);
        }
    }

    public void nextRequest() {
        response.recycle();
        for (int i = 0; i <= lastActiveFilter; i++) {
            activeFilters[i].recycle();
        }
        // Reset pointers
        pos = 0;
        lastActiveFilter = -1;
        finished = false;
        committed = false;
    }

    /**
     * 做一些收尾动作
     */
    public void endRequest() throws IOException{
        if (finished) {
            return;
        }
        if (lastActiveFilter != -1) {
            activeFilters[lastActiveFilter].end();
        }
        finished = true;
    }

    /**
     * 真正使用顶层stream输出字节
     */
    protected class OutputStreamOutputBuffer implements OutputBuffer {
        @Override
        public int doWrite(ByteChunk chunk, Response response) throws IOException {
            System.out.print(new String(chunk.getBuff(),chunk.getStart(),chunk.getLength()));
            outputStream.write(chunk.getBuff(),chunk.getStart(),chunk.getLength());
            return chunk.getLength();
        }
    }
}
